package com.example.grpc.unary;

import com.example.grpc.client.HeaderClientInterceptor;
import com.google.protobuf.Descriptors;
import com.google.protobuf.DynamicMessage;
import io.grpc.*;
import io.grpc.Channel;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;
import io.grpc.protobuf.ProtoUtils;
import io.grpc.stub.ClientCalls;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http2.*;
import io.netty.handler.ssl.SslProvider;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class DynamicUnaryCallClient {
    public static void main(String[] args) throws InterruptedException {/*
        final EventLoopGroup clientWorkerGroup = new NioEventLoopGroup();
        final Bootstrap b = new Bootstrap();
        b.group(clientWorkerGroup);
        b.channel(NioSocketChannel.class);
        b.remoteAddress("127.0.0.1", 10511);
        b.handler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                ChannelPipeline pipeline = socketChannel.pipeline();
                Http2FrameCodec http2FrameCodec = Http2FrameCodecBuilder.forClient().autoAckSettingsFrame(true).validateHeaders(true).autoAckPingFrame(true).build();
                pipeline.addLast(http2FrameCodec);
                pipeline.addLast(new ChannelInboundHandlerAdapter() {
                    @Override
                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                        if (msg instanceof Http2StreamFrame) {
                            Http2StreamFrame streamFrame = (Http2StreamFrame) msg;
                            log.info("stream id:{}, state: {}", streamFrame.stream().id(), streamFrame.stream().state());
                        }
                        // 判断stream是否endStream
                        if (msg instanceof Http2DataFrame) {
                            Http2DataFrame dataFrame = (Http2DataFrame) msg;
                            log.info("接收到 Http2DataFrame:{}", dataFrame.content().getCharSequence(0, 33, CharsetUtil.UTF_8));
                            if (dataFrame.isEndStream()) {
                                log.info("服务端响应结束");
                            }
                        } else if (msg instanceof Http2HeadersFrame) {
                            log.info("接收到 Http2HeadersFrame");
                            Http2HeadersFrame headersFrame = (Http2HeadersFrame) msg;
                            if (headersFrame.isEndStream()) {
                                log.info("服务端响应结束");
                            }

                        } else if (msg instanceof Http2SettingsFrame) {
                            Http2SettingsFrame settingsFrame = (Http2SettingsFrame) msg;
                            log.info("接收到 Http2SettingsFrame:{}", settingsFrame.name());
                        } else if (msg instanceof Http2SettingsAckFrame) {
                            Http2SettingsAckFrame ackFrame = (Http2SettingsAckFrame) msg;
                            log.info("接收到 Http2SettingsAckFrame:{}", ackFrame.name());
                            Http2Headers headers = new DefaultHttp2Headers();
                            headers.add(":path", "/proxy.Greeter/SayHello");
                            headers.add(":method", "POST");
                            headers.add(":scheme", "http");
                            headers.add(":te", "trailers");
                            headers.add(":content-type", "application/grpc");
                            headers.add(":content-type", "application/grpc");
                            headers.add(":content-type", "application/grpc");
                            headers.add(":user-agent", "grpc-java-netty/1.43.1");
                            Http2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(headers, false);
                            log.info("send request header:{}", headersFrame.headers());
                            ctx.writeAndFlush(headersFrame);
                            Http2DataFrame dataFrame = new DefaultHttp2DataFrame(Unpooled.copiedBuffer("jerry.".getBytes(StandardCharsets.UTF_8)), true);
                            ctx.writeAndFlush(dataFrame);
                        } else if (msg instanceof Http2GoAwayFrame) {
                            log.info("服务端主动关闭了连接.");
                        } else if (msg instanceof Http2PingFrame){
                            Http2PingFrame pingFrame = (Http2PingFrame) msg;
                            log.info("接收到 PING FRAME received:{}", pingFrame.content());
                        } else if (msg instanceof Http2ResetFrame) {
                            Http2ResetFrame resetFrame = (Http2ResetFrame) msg;
                            log.info("接收到 RST FRAME, errorCode:{}", resetFrame.errorCode());
                        } else {
                            log.error("unknown frame");
                        }
                    }
                });
            }
        });
        ChannelFuture channel = b.connect().sync();*/

        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("service", "hello");
        headerMap.put("src-party-id", "9999");
        headerMap.put("src-role", "proxy");
        headerMap.put("dest-party-id", "300");
        headerMap.put("dest-role", "guest");
        System.out.println(SslProvider.isAlpnSupported(SslProvider.JDK));
        Http2Connection connection = new DefaultHttp2Connection(false);
        HttpToHttp2ConnectionHandler connectionHandler = new HttpToHttp2ConnectionHandlerBuilder().frameListener(new DelegatingDecompressorFrameListener(connection, new InboundHttp2ToHttpAdapterBuilder(connection)
                        .propagateSettings(true).build()))
                .connection(connection)
                .frameListener(new Http2FrameListener() {
                    @Override
                    public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding, boolean endOfStream) throws Http2Exception {
                        return 0;
                    }

                    @Override
                    public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding, boolean endOfStream) throws Http2Exception {

                    }

                    @Override
                    public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency, short weight, boolean exclusive, int padding, boolean endOfStream) throws Http2Exception {

                    }

                    @Override
                    public void onPriorityRead(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight, boolean exclusive) throws Http2Exception {

                    }

                    @Override
                    public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {

                    }

                    @Override
                    public void onSettingsAckRead(ChannelHandlerContext ctx) throws Http2Exception {

                    }

                    @Override
                    public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception {

                    }

                    @Override
                    public void onPingRead(ChannelHandlerContext ctx, long data) throws Http2Exception {

                    }

                    @Override
                    public void onPingAckRead(ChannelHandlerContext ctx, long data) throws Http2Exception {

                    }

                    @Override
                    public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId, Http2Headers headers, int padding) throws Http2Exception {

                    }

                    @Override
                    public void onGoAwayRead(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData) throws Http2Exception {

                    }

                    @Override
                    public void onWindowUpdateRead(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement) throws Http2Exception {

                    }

                    @Override
                    public void onUnknownFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags, ByteBuf payload) throws Http2Exception {

                    }
                }).build();

    }
}
